// Package app 需要注册的后台服务
package app

import (
	"ams_client/daemon/tcp"
	"ams_client/dao"
	"context"
	"github.com/sirupsen/logrus"
	"golang.org/x/sync/errgroup"
	"lib/structs/ams"
	"lib/utils"
	"time"
)

type Daemon struct {
	exitFunc  context.CancelFunc
	amsClient *tcp.Client
}

func NewDaemon() *Daemon {
	return &Daemon{}
}

// Run runs the service and blocks until complete.
func (d *Daemon) Run(parentCtx context.Context) {
	var (
		g   errgroup.Group
		err error
	)
	ctx, cancelFunc := context.WithCancel(parentCtx)
	d.exitFunc = cancelFunc
	// 初始化数据库
	err = dao.InitDB()
	if err != nil {
		logrus.Errorf("global.InitDB(),err:[%v]", err)
		return
	}
	// 初始化客户端连接
	d.amsClient = tcp.InitAmsClient()

	// 程序启动时强制执行一次部分策略
	g.Go(func() error {
		tcp.Handler.ExecPolicyForEvent("boot")
		return nil
	})

	// 周期扫描本地需要执行的策略,同时上报数据
	g.Go(func() error {
		ticker := time.NewTicker(time.Duration(ams.PolicyScanTime) * time.Second)
		defer ticker.Stop()
		for range ticker.C {
			go func() {
				// 执行策略
				tcp.Handler.ExecPolicyForRang()
				// 上传数据
				if d.amsClient.ClientId == 0 {
					d.amsClient.Ping(0)
				} else {
					li := tcp.Handler.GetUploadLog()
					for _, v := range li {
						d.amsClient.Writer(ams.TcpResponse{
							ResCode:    ams.ResCode.UploadLog,
							ResContent: utils.Obj2Str(v),
						})
						dao.LogMapCache.Delete(v.Id)
					}
				}
			}()
		}
		return nil
	})

	// 发送心跳
	g.Go(func() error {
		ticker := time.NewTicker(time.Duration(ams.TcpHeartbeatInterval) * time.Second)
		defer ticker.Stop()
		for range ticker.C {
			d.amsClient.Ping(0)
		}
		return nil //nolint
	})

	// 优雅关闭
	g.Go(func() error {
		defer func() {
			logrus.Debug("优雅关闭,协程-已退出")
			cancelFunc()
		}()
		<-ctx.Done()
		return nil //nolint
	})
	err = g.Wait()
	if err != nil {
		logrus.Debugf("shutting down the server: %v", err)
	}

}
